package com.galeno.api;

import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.*;
import org.apache.hadoop.hbase.client.*;
import org.apache.hadoop.hbase.util.Bytes;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;

/**
 * 获取hbase客户端对象 调用方法 核心对象:table 和表有关的操作 DML admin 管理对象 DDL Tools split flush....
 *
 * @author galeno @Title: @Description:
 * @date 2021/8/122:06
 */
public class HbaseUtil {
  static Connection con = null;
  static Configuration conf = null;
  static Admin admin = null;

  static {
    conf = HBaseConfiguration.create();
    // 创建Hbase连接
    try {
      con = ConnectionFactory.createConnection(conf);
      // 要创建表,删除表,需要和HMaster进行连接,所以需要有一个Admin对象
      admin = con.getAdmin();
    } catch (IOException e) {
      e.printStackTrace();
    }
  }

  /**
   * 创建表
   *
   * @param tableName
   * @param columnFamilys
   * @throws IOException
   */
  public static void createTable(String tableName, String... columnFamilys) throws IOException {
    TableName tableName1 = TableName.valueOf(tableName);
    if (admin.tableExists(tableName1)) {
      System.out.println("表已经存在");
      return;
    }
    ArrayList<ColumnFamilyDescriptorBuilder> cfdbList = new ArrayList<>();
    ArrayList<ColumnFamilyDescriptor> lList = new ArrayList<>();
    // 构建表描述构建器
    TableDescriptorBuilder tdb = TableDescriptorBuilder.newBuilder(tableName1);
    for (String columnFamily : columnFamilys) {
      // 列族描述器构造器
      ColumnFamilyDescriptorBuilder cfdb =
          ColumnFamilyDescriptorBuilder.newBuilder(Bytes.toBytes(columnFamily));
      cfdbList.add(cfdb);
    }
    // 获得列描述器
    for (ColumnFamilyDescriptorBuilder columnFamilyDescriptorBuilder : cfdbList) {
      ColumnFamilyDescriptor columnFamilyDescriptor = columnFamilyDescriptorBuilder.build();
      lList.add(columnFamilyDescriptor);
    }
    // 添加列族
    for (ColumnFamilyDescriptor columnFamilyDescriptor : lList) {
      tdb.setColumnFamily(columnFamilyDescriptor);
    }
    TableDescriptor td = tdb.build();
    admin.createTable(td);
    System.out.println("表创建成功");
  }

  /**
   * 向表中插入数据
   *
   * @param tableName 要插入的表名
   * @param rowKey 行键
   * @param confamily 列族
   * @param type 列族属性
   * @param value 值
   * @throws IOException
   */
  public static void insertData(
      String tableName, String rowKey, String confamily, String type, String value)
      throws IOException {
    Table table = con.getTable(TableName.valueOf(tableName));
    Put put = new Put(Bytes.toBytes(rowKey));
    put.addColumn(Bytes.toBytes(confamily), Bytes.toBytes(type), Bytes.toBytes(value));
    table.put(put);
  }

  /**
   * 显示所有表
   *
   * @throws IOException
   */
  public static void showAllTables() throws IOException {
    TableName[] tableNames = admin.listTableNames();
    List<TableName> tableNames1 = Arrays.asList(tableNames);
    System.out.println(tableNames1);
  }

  /**
   * 获取命名空间下的所有表
   *
   * @param nameSpace 命名空间
   */
  public static void showAllTables(String nameSpace) throws IOException {
    TableName[] tableNames = admin.listTableNamesByNamespace(nameSpace);
    for (TableName tableName : tableNames) {
      System.out.println(tableName.getNameAsString());
    }
  }

  /**
   * 根据正则表达式获取表
   *
   * @throws IOException
   */
  public static void showAllTablesReg(String reg) throws IOException {
    HTableDescriptor[] tables = admin.listTables(reg);
    for (HTableDescriptor table : tables) {
      TableName tableName = table.getTableName();
      System.out.println(tableName.getNameAsString());
    }
  }

  public static void hbClose() throws IOException {
    admin.close();
    con.close();
  }

  /**
   * @param tableName 表名
   * @param rowKey 行键
   * @param comFa 列族
   * @param attr 属性
   * @param value 值
   * @param time 刷写周期时间
   * @throws IOException
   */
  public static void insertData(
      String tableName, String rowKey, String comFa, String attr, String value, Long time)
      throws IOException {
    BufferedMutator mutator = con.getBufferedMutator(TableName.valueOf(tableName));
    Put put = new Put(Bytes.toBytes(rowKey));
    // 添加单元格
    put.addColumn(Bytes.toBytes(comFa), Bytes.toBytes(attr), Bytes.toBytes(value));
    mutator.setWriteBufferPeriodicFlush(time);
    mutator.mutate(put);

    /*    mutator.setOperationTimeout(2000);  操作时间
       mutator.setRpcTimeout(1000);  连接时间
       RPC 远程方法调用  远程过程调用  网络请求 调用方法 完成功能
    */
    // 强制刷写
    // mutator.flush();
  }

  /**
   * @param tableName
   * @throws IOException
   */
  public static void getDataWay1(String tableName) throws IOException {
    Table table = con.getTable(TableName.valueOf(tableName));
    Scan scan = new Scan();
    ResultScanner resultScanner = table.getScanner(scan);
    // Result行
    Iterator<Result> resultIterator = resultScanner.iterator();
    while (resultIterator.hasNext()) {
      // 获取行数据
      Result rowData = resultIterator.next();
      // rowData代表行数据   行中有单元格   每行的单元格个数
      while (rowData.advance()) { // 当前行是否有下一个单元格
        // 获取单元格   遍历单元格
        Cell cell = rowData.current();
        System.out.println(cell);
      }
    }
  }

  public static void getDataWay2(String tableName) throws IOException {
    Table table = con.getTable(TableName.valueOf(tableName));
    Scan scan = new Scan();
    // 全表扫描  多行数据
    ResultScanner resultScanner = table.getScanner(scan);
    // result多行
    Iterator<Result> resultIterator = resultScanner.iterator();
    // int count = 0;
    while (resultIterator.hasNext()) {
      // count++;
      // System.out.print("这是第" + count + "行数据");
      System.out.println();
      // 获取行数据
      Result rowData = resultIterator.next();
      while (rowData.advance()) {
        // 获取单元格,遍历单元格
        Cell cell = rowData.current();
        //  解析单元格
        byte[] cloneRow = CellUtil.cloneRow(cell);
        byte[] cloneFamily = CellUtil.cloneFamily(cell);
        byte[] cloneQualifier = CellUtil.cloneQualifier(cell);
        byte[] cloneValue = CellUtil.cloneValue(cell);
        System.out.print(
            new String(cloneRow)
                + ":"
                + new String(cloneFamily)
                + ":"
                + new String(cloneQualifier)
                + ":"
                + new String(cloneValue));
      }
    }
  }

  /**
   * @param tableName
   * @throws IOException
   */
  public static void getDataWay3(String tableName) throws IOException {
    Table table = con.getTable(TableName.valueOf(tableName));
    Scan scan = new Scan();
    ResultScanner resultScanner = table.getScanner(scan);
    Iterator<Result> resultIterator = resultScanner.iterator();
    while (resultIterator.hasNext()) {
      Result result = resultIterator.next();
      HbaseUtil.showData(result);
    }
  }

  /**
   * 根据rowkey删除表中的记录
   *
   * @param tableName
   * @param rowKey
   * @throws IOException
   */
  public static void deleteAsRowKey(String tableName, String rowKey) throws IOException {
    // 1.获取HTable对象
    Table table = con.getTable(TableName.valueOf(tableName));
    // 2.根据rowkey构建delete对象
    Delete delete = new Delete(Bytes.toBytes(rowKey));
    // 3.执行delete请求
    table.delete(delete);
    // 4.关闭表,自己调用close关闭
    System.out.println("删除成功");
  }

  /**
   * 获取数据
   *
   * @param tableName
   * @param rowKeys 行键,可以输入多个
   * @throws IOException
   */
  public static void getData(String tableName, String... rowKeys) throws IOException {
    Table tb = con.getTable(TableName.valueOf(tableName));
    List<Get> getList = new ArrayList<>();
    for (String rowKey : rowKeys) {
      getList.add(new Get(Bytes.toBytes(rowKey)));
    }
    Result[] results = tb.get(getList);
    for (Result result : results) {
      HbaseUtil.showData(result);
    }
  }

  /**
   * 显示一行一行数据
   *
   * @param result
   */
  public static void showData(Result result) {
    while (result.advance()) {
      Cell cell = result.current();
      String rowStr = new String(CellUtil.cloneRow(cell));
      String familyStr = new String(CellUtil.cloneFamily(cell));
      String qualifierStr = new String(CellUtil.cloneQualifier(cell));
      String valueStr = new String(CellUtil.cloneValue(cell));
      System.out.println(rowStr + "-" + familyStr + "-" + qualifierStr + "-" + valueStr);
    }
  }

  /**
   * 根据列族获取数据
   *
   * @param tableName
   * @param rowKey
   * @param conFams
   * @throws IOException
   */
  public static void getDateUseFamily(String tableName, String rowKey, String... conFams)
      throws IOException {
    Table table = con.getTable(TableName.valueOf(tableName));
    Get get = new Get(Bytes.toBytes(rowKey));
    // 设置列族  查询列族数据
    for (String conFam : conFams) {
      get.addFamily(Bytes.toBytes(conFam));
    }
    Result result = table.get(get);
    HbaseUtil.showData(result);
  }

  /**
   * 根据表,列族,和属性获取数据
   *
   * @param tableName 表名
   * @param rowKey 行键
   * @param conFamList 列族封装到数组
   * @param shuxingList 属性封装到数组
   * @throws IOException
   */
  public static void getDataUseDanYuanGe(
      String tableName, String rowKey, ArrayList<String> conFamList, ArrayList<String> shuxingList)
      throws IOException {
    Table table = con.getTable(TableName.valueOf(tableName));
    Get get = new Get(Bytes.toBytes(rowKey));
    for (String confa : conFamList) {
      for (String shuxing : shuxingList) {
        get.addColumn(Bytes.toBytes(confa), Bytes.toBytes(shuxing));
      }
    }
    Result result = table.get(get);
    HbaseUtil.showData(result);
  }

  /**
   * 创建命名空间
   *
   * @param nameSpace
   */
  public static void createNameSpace(String nameSpace) throws IOException {
    NamespaceDescriptor.Builder builder = NamespaceDescriptor.create(nameSpace);
    NamespaceDescriptor namespaceDescriptor = builder.build();
    admin.createNamespace(namespaceDescriptor);
    System.out.println("创建命名空间" + nameSpace + "成功");
  }
  // TODO
  public static void allNameSpace() {}

  /**
   * 根据表名,列族以及属性删除表中的元素
   *
   * @param tableName
   * @param rowKey
   * @param conFAs
   * @throws IOException
   */
  public static void delete(String tableName, String rowKey, String... conFAs) throws IOException {
    Table table = con.getTable(TableName.valueOf(tableName));
    Delete delete = new Delete(Bytes.toBytes(rowKey));
    for (String conFA : conFAs) {
      delete.addFamily(Bytes.toBytes(conFA));
    }
    table.delete(delete);
  }

  /**
   * 删除命名空间
   *
   * @param nameSpace
   * @throws IOException
   */
  public static void deleteNameSpace(String nameSpace) throws IOException {
    admin.deleteNamespace(nameSpace);
    System.out.println("删除成功");
  }

  /**
   * 根据表名删除表,可以传入多个表
   *
   * @param tableNames
   * @throws IOException
   */
  public static void dropTable(String... tableNames) throws IOException {

    ArrayList<TableName> tableNameArrayList = new ArrayList<>();
    for (String tableName : tableNames) {
      TableName tab = TableName.valueOf(tableName);
      tableNameArrayList.add(tab);
    }
    for (TableName tableName : tableNameArrayList) {
      if (admin.tableExists(tableName)) {
        admin.disableTable(tableName);
        if (admin.isTableDisabled(tableName)) {
          admin.deleteTable(tableName);
          System.out.println("删除成功");
        }
      }
    }
  }
}
